﻿// ===============================================================================
// XCI.NET 西安交通信息WinForm开发框架 2018 版权所有
// ===============================================================================

using System.Collections;
using System.Collections.Generic;
using XCI.Extensions;
using XCI.Helper;

namespace XCI.Core
{
    /// <summary>
    /// 通用字典
    /// </summary>
    public class Map : Dictionary<string, object>
    {
        public static Map New => new Map();

        /// <summary>
        /// 添加键值对
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        public Map Set(string key, object value)
        {
            this[key] = value;
            return this;
        }

        /// <summary>
        /// 添加对象(属性名为键,属性值为值)
        /// </summary>
        /// <param name="objs">对象</param>
        public Map AddObject(params object[] objs)
        {
            if (objs == null || objs.Length == 0) return this;
            foreach (var obj in objs)
            {
                if (obj == null) continue;
                var data = ObjectHelper.GetPropertyKeyValuePair(obj);
                foreach (KeyValuePair<string, object> item in data)
                {
                    this[item.Key] = item.Value;
                }
            }
            return this;
        }

        /// <summary>
        /// 如果值不为空字符串,则添加键值对
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        public Map IfNotEmptyAdd(string key, object value)
        {
            if (value != null && !string.IsNullOrEmpty(value.ToString()))
            {
                this[key] = value.ToString();
            }
            return this;
        }

        /// <summary>
        /// 如果值不为空对象,则添加键值对
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        public Map IfNotNullAdd(string key, object value)
        {
            if (value != null)
            {
                this[key] = value.ToString();
            }
            return this;
        }

        /// <summary>
        /// 如果条件为真,则添加键值对
        /// </summary>
        /// <param name="condition">条件</param>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        public Map IfAdd(bool condition, string key, object value)
        {
            if (condition)
            {
                this[key] = value;
            }
            return this;
        }

        /// <summary>
        /// 合并两个Map集合
        /// </summary>
        /// <param name="map">待合并的Map集合</param>
        public Map Merge(Map map)
        {
            if (map == null) return this;

            foreach (KeyValuePair<string, object> item in map)
            {
                this[item.Key] = item.Value;
            }
            return this;
        }
    }

    /// <summary>
    /// 字符串字典
    /// </summary>
    public class SMap : Dictionary<string, string>
    {
        public static SMap New => new SMap();

        /// <summary>
        /// 添加键值对
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        public SMap Set(string key, string value)
        {
            this[key] = value;
            return this;
        }

        /// <summary>
        /// 添加对象(属性名为键,属性值为值)
        /// </summary>
        /// <param name="obj">对象</param>
        public SMap AddObject(string obj)
        {
            var data = ObjectHelper.GetPropertyKeyValuePair(obj);
            foreach (KeyValuePair<string, object> item in data)
            {
                this[item.Key] = item.Value.ToStringOrEmpty();
            }
            return this;
        }

        /// <summary>
        /// 如果值不为空字符串,则添加键值对
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        public SMap IsNotEmpty(string key, string value)
        {
            if (value.IsNotEmpty())
            {
                this[key] = value;
            }
            return this;
        }

        /// <summary>
        /// 如果条件为真,则添加键值对
        /// </summary>
        /// <param name="condition">条件</param>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        public SMap If(bool condition, string key, string value)
        {
            if (condition)
            {
                this[key] = value;
            }
            return this;
        }

        /// <summary>
        /// 合并两个Map集合
        /// </summary>
        /// <param name="map">待合并的Map集合</param>
        public SMap Merge(SMap map)
        {
            foreach (KeyValuePair<string, string> item in map)
            {
                this[item.Key] = item.Value;
            }
            return this;
        }
    }

    public class MapOrdered<TKey, TValue> : IDictionary<TKey, TValue>
    {
        #region Private Data members
        private readonly IList<TKey> _list = null;
        private readonly IDictionary<TKey, TValue> _map = null;
        #endregion


        #region Constructors
        public MapOrdered()
        {
            _list = new List<TKey>();
            _map = new Dictionary<TKey, TValue>();
        }
        #endregion


        #region IDictionary<TKey,TValue> Members
        /// <summary>
        /// Add to key/value for both forward and reverse lookup.
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        public void Add(TKey key, TValue value)
        {
            // Add to map and list.
            _map.Add(key, value);
            _list.Add(key);
        }

        /// <summary>
        /// Determine if the key is contain in the forward lookup.
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool ContainsKey(TKey key)
        {
            return _map.ContainsKey(key);
        }

        /// <summary>
        /// Get a list of all the keys in the forward lookup.
        /// </summary>
        public ICollection<TKey> Keys => _map.Keys;


        /// <summary>
        /// Remove the key from the ordered dictionary.
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool Remove(TKey key)
        {
            // Check.
            if (!_map.ContainsKey(key)) return false;

            int ndxKey = IndexOfKey(key);
            _map.Remove(key);
            _list.RemoveAt(ndxKey);
            return true;
        }

        /// <summary>
        /// Try to get the value from the forward lookup.
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool TryGetValue(TKey key, out TValue value)
        {
            return _map.TryGetValue(key, out value);
        }

        /// <summary>
        /// Get the collection of values.
        /// </summary>
        public ICollection<TValue> Values => _map.Values;

        /// <summary>
        /// Set the key / value for bi-directional lookup.
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public TValue this[TKey key]
        {
            get => _map[key];
            set => _map[key] = value;
        }
        #endregion


        #region ICollection<KeyValuePair<TKey,TValue>> Members
        /// <summary>
        /// Add to ordered lookup.
        /// </summary>
        /// <param name="item"></param>
        public void Add(KeyValuePair<TKey, TValue> item)
        {
            this.Add(item);
        }

        /// <summary>
        /// Clears keys/value for bi-directional lookup.
        /// </summary>
        public void Clear()
        {
            _map.Clear();
            _list.Clear();
        }


        /// <summary>
        /// Determine if the item is in the forward lookup.
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public bool Contains(KeyValuePair<TKey, TValue> item)
        {
            return _map.Contains(item);
        }


        /// <summary>
        /// Copies the array of key/value pairs for both ordered dictionary.
        /// TO_DO: This needs to implemented.
        /// </summary>
        /// <param name="array"></param>
        /// <param name="arrayIndex"></param>
        public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
        {
            _map.CopyTo(array, arrayIndex);
        }


        /// <summary>
        /// Get number of entries.
        /// </summary>
        public int Count => _map.Count;


        /// <summary>
        /// Get whether or not this is read-only.
        /// </summary>
        public bool IsReadOnly => _map.IsReadOnly;


        /// <summary>
        /// Remove the item.
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public bool Remove(KeyValuePair<TKey, TValue> item)
        {
            // Check.
            if (!_map.ContainsKey(item.Key)) return false;

            int ndxOfKey = IndexOfKey(item.Key);
            _list.RemoveAt(ndxOfKey);
            return _map.Remove(item);
        }
        #endregion


        #region IEnumerable<KeyValuePair<TKey,TValue>> Members
        /// <summary>
        /// Get the enumerator for the forward lookup.
        /// </summary>
        /// <returns></returns>
        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
        {
            return _map.GetEnumerator();
        }
        #endregion


        #region IEnumerable Members
        /// <summary>
        /// Get the enumerator for the forward lookup.
        /// </summary>
        /// <returns></returns>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return _map.GetEnumerator();
        }
        #endregion


        #region IList methods
        /// <summary>
        /// Insert key/value at the specified index.
        /// </summary>
        /// <param name="index"></param>
        /// <param name="key"></param>
        /// <param name="value"></param>
        public void Insert(int index, TKey key, TValue value)
        {
            // Add to map and list.
            _map.Add(key, value);
            _list.Insert(index, key);
        }


        /// <summary>
        /// Get the index of the key.
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public int IndexOfKey(TKey key)
        {
            if (!_map.ContainsKey(key)) return -1;

            for (int ndx = 0; ndx < _list.Count; ndx++)
            {
                TKey keyInList = _list[ndx];
                if (keyInList.Equals(key))
                    return ndx;
            }
            return -1;
        }


        /// <summary>
        /// Remove the key/value item at the specified index.
        /// </summary>
        /// <param name="index"></param>
        public void RemoveAt(int index)
        {
            TKey key = _list[index];
            _map.Remove(key);
            _list.RemoveAt(index);
        }


        /// <summary>
        /// Get/set the value at the specified index.
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public TValue this[int index]
        {
            get
            {
                TKey key = _list[index];
                return _map[key];
            }
            set
            {
                TKey key = _list[index];
                _map[key] = value;
            }
        }
        #endregion

    }
}